package cn.tataben.database.selector;

import com.tencent.wcdb.Cursor;

import java.util.ArrayList;
import java.util.List;

import cn.tataben.database.DB;
import cn.tataben.database.table.Table;
import cn.tataben.database.util.CursorUtils;

/**
 * 查询语句
 * @author tataben
 * @param <T>
 */
public final class Selector<T> {

    private DB db;
    private int limit = 0;
    private int offset = 0;
    private Where whereBuilder;
    private final Table<T> table;
    private List<OrderBy> orderByList;

    /**
     * 构造私有化
     * @param table
     */
    private Selector(Table<T> table, DB db) throws Exception {
        db.createTable(table);
        this.table = table;
        this.db = db;
    }
    /**
     * 静态实例
     * @param table
     * @param <T>
     * @return
     */
    public static <T> Selector<T> from(Table<T> table, DB db) throws Exception {
        return new Selector<>(table, db);
    }

    /**
     * WHERE 语句
     * @param columnName
     * @param op
     * @param value
     * @return
     */
    public Selector<T> where(String columnName, String op, Object value) {
        this.whereBuilder = Where.b(columnName, op, value);
        return this;
    }

    /**
     * AND 语句
     * @param columnName
     * @param op
     * @param value
     * @return
     */
    public Selector<T> and(String columnName, String op, Object value) {
        this.whereBuilder.and(columnName, op, value);
        return this;
    }

    /**
     * OR 语句
     * @param columnName
     * @param op
     * @param value
     * @return
     */
    public Selector<T> or(String columnName, String op, Object value) {
        this.whereBuilder.or(columnName, op, value);
        return this;
    }

    /**
     * ORDER BY 语句
     * @param columnName
     * @return
     */
    public Selector<T> orderBy(String columnName) {
        return this.orderBy(columnName, false);
    }
    public Selector<T> orderBy(String columnName, boolean desc) {
        if (orderByList == null) {
            orderByList = new ArrayList<>();
        }
        orderByList.add(new OrderBy(columnName, desc));
        return this;
    }

    /**
     * LIMIT 语句
     * @param limit
     * @param offset
     * @return
     */
    public Selector<T> limit(int limit, int offset) {
        this.offset = offset;
        this.limit = limit;
        return this;
    }
    public Selector<T> limit(int limit) {
        return this.limit(limit, 0);
    }

    /**
     * 转换成SQL字符串
     * @return
     */
    @Override
    public String toString() {
        StringBuilder result = new StringBuilder();
        result.append("SELECT * FROM ").append("\"").append(table.getName()).append("\"");
        if (whereBuilder != null && whereBuilder.getWhereItemSize() > 0) {
            result.append(" WHERE ").append(whereBuilder.toString());
        }
        if (orderByList != null && orderByList.size() > 0) {
            result.append(" ORDER BY ");
            for (OrderBy orderBy : orderByList) {
                result.append(orderBy.toString()).append(',');
            }
            result.deleteCharAt(result.length() - 1);
        }
        if (limit > 0) {
            result.append(" LIMIT ").append(limit);
            result.append(" OFFSET ").append(offset);
        }
        return result.toString();
    }

    /**
     * 查询单个实体
     * @return
     * @throws Exception
     */
    public T find() throws Exception {
        Cursor cursor = db.execQuery(this.limit(1).toString());
        if (cursor != null) {
            try {
                if (cursor.moveToNext()) {
                    return CursorUtils.getEntity(table, cursor);
                }
            } catch (Throwable e) {
                throw new Exception(e);
            } finally {
                CursorUtils.closeQuietly(cursor);
            }
        }
        return null;
    }

    /**
     * 查询多个实体
     * @return
     * @throws Exception
     */
    public List<T> findAll() throws Exception {
        Cursor cursor = db.execQuery(this.toString());
        if (cursor != null) {
            try {
                List<T> result = new ArrayList<>();
                while (cursor.moveToNext()) {
                    result.add(CursorUtils.getEntity(table, cursor));
                }
                return result;
            } catch (Throwable e) {
                throw new Exception(e);
            } finally {
                CursorUtils.closeQuietly(cursor);
            }
        }
        return null;
    }

    /**
     * 排序
     * @author tataben
     */
    public static class OrderBy {
        private String columnName;
        private boolean desc;

        public OrderBy(String columnName, boolean desc) {
            this.columnName = columnName;
            this.desc = desc;
        }

        @Override
        public String toString() {
            return "\"" + columnName + "\"" + (desc ? " DESC" : " ASC");
        }
    }
}
